/**
 * @file FuncPattern.hh
 * @author Xiaoze Lin (linxiaoze96@gmail.com)
 * @brief The functional pattern class.
 * @version 0.1
 *
 * @copyright Copyright (c) 2024
 *
 */
#pragma once

#include <string>

#include "NetlistManager.hh"
#include "Value.hh"
#include "verilog-vcd-parser/src/VCDFileParser.hpp"

namespace ifsim {

struct ToggledGate
{
  Value v;   // the gate evaluation value in the simulation frame
  uint gid;  // the gate id after levelization and optimization
};

class FuncPattern
{
 public:
  FuncPattern();
  ~FuncPattern();

 private:
};

class FuncPatternManager
{
 public:
  FuncPatternManager();
  ~FuncPatternManager();

  bool readFuncPattern(std::string vcd_file);
  void getNetlistInfo();
  bool parseVCDfile(std::string file);
  bool mapVCDsignalsToGid();
  bool mapOneVCDsignalToGid(std::string signal_name, int& pi_gid, int& po_gid);

  void getToggledStiAndResponsePerFrame();
  void getFrame0ToggledStiAndResponse(std::vector<ToggledGate>& sti, std::vector<std::vector<Value>>& first_sti);
  void convertVCDValToPatVal(u_char vcd_val, Value& pat_val);

  const std::vector<ToggledGate>& getToggledStimuli() const { return _toggledSti; }
  const std::vector<Value>& getResponse(int frame_id) const { return _response[frame_id]; };

  void setToggledGate(std::vector<ToggledGate>& tp, uint gid, Value v)
  {
    ToggledGate tin = {v, gid};
    tp.push_back(tin);
  }

  void getToggledGate(uint n, uint& gid, Value& v) const
  {
    ToggledGate tin = _toggledSti[n];
    gid = tin.gid;
    v = tin.v;
  }

  uint getFrameBegin(int frame) const { return _stiFrameBegin[frame]; }
  uint getToggledPISize(int frame) const { return (_stiFrameBegin[frame + 1] - _stiFrameBegin[frame]); }
  int frameNum() const { return (_stiFrameBegin.size() - 1); }

 private:
  VCDFileParser _parser;
  VCDFile* _trace;

  // The index is the same in _signals and _gids
  std::vector<VCDSignal*>* _signals;
  std::vector<std::vector<int>> _gids;  // The corresponding gate ID associated with the signal

  std::vector<ToggledGate> _toggledSti;  // toggled PI stimuli
  std::vector<uint> _stiFrameBegin;      // the index of frame front toggled gate

  // 1st dim -> different time frame, 2nd dim -> diffetent PO
  std::vector<std::vector<Value>> _response;  // PO response

  // netlist info
  const SimGate* _gates;
  int _numPIs;
  int _numPOs;
  int _firstPO;

  NetlistManager* _netlistManager;
};
}  // namespace ifsim